package com.nuanshui.framework.utils.redis;

import java.util.Random;

import redis.clients.jedis.Jedis;

public class RedisLock {  
  
    /** 加锁标志 */  
    public static final String LOCKED = "TRUE";  
    /** 毫秒与毫微秒的换算单位 1毫秒 = 1000000毫微秒 */  
    public static final long MILLI_NANO_CONVERSION = 1000 * 1000L;  
    /** 默认超时时间（毫秒） */  
    public static final long DEFAULT_TIME_OUT = 2000;  
    public static final Random RANDOM = new Random();  
    /** 锁的超时时间（秒），过期删除 */  
    public static final int EXPIRE = 3 * 60;  
    private MasterSlavePool masterSlavePool;  
    // 锁状态标志  
    private boolean locked = false;  
  
    /** 
     * This creates a RedisLock 
     * @param key key 
     * @param shardedJedisPool 数据源 
     */  
    public  RedisLock(MasterSlavePool masterSlavePool) {    
        this.masterSlavePool = masterSlavePool;  
        
    }  
  
    /** 
     * 加锁 
     * 应该以： 
     * lock(); 
     * try { 
     *      doSomething(); 
     * } finally { 
     *      unlock()； 
     * } 
     * 的方式调用  
     * @param timeout 超时时间 
     * @return 成功或失败标志 
     */  
    public boolean lock(String key,long timeout) { 
    	 Jedis jedis = this.masterSlavePool.getMasterResource();
    	try {
    		long nano = System.nanoTime();  
            timeout *= MILLI_NANO_CONVERSION;          
            try {  
                while ((System.nanoTime() - nano) < timeout) {  
                    if (jedis.setnx(key, LOCKED) == 1) {  
                        jedis.expire(key, EXPIRE);  
                        this.locked = true; 
                        break;
                    }  
                    // 短暂休眠，避免出现活锁  
                    Thread.sleep(3, RANDOM.nextInt(500));  
                }  
            } catch (Exception e) {  
            	e.printStackTrace();
                throw new RuntimeException("Locking error", e);  
            } 
		} finally {
			this.masterSlavePool.returnResource(jedis);			
		}
         
        return this.locked;  
    }  
  
    /** 
     * 加锁 
     * 应该以： 
     * lock(); 
     * try { 
     *      doSomething(); 
     * } finally { 
     *      unlock()； 
     * } 
     * 的方式调用 
     * @param timeout 超时时间 
     * @param expire 锁的超时时间（秒），过期删除 
     * @return 成功或失败标志 
     */  
    public boolean lock(String key,long timeout, int expire) {  
    	 Jedis jedis = this.masterSlavePool.getMasterResource();
    	try {
    		long nano = System.nanoTime();  
            timeout *= MILLI_NANO_CONVERSION;        
            try {  
                while ((System.nanoTime() - nano) < timeout) {  
                    if (jedis.setnx(key, LOCKED) == 1) {  
                        jedis.expire(key, expire);  
                        this.locked = true;  
                    }  
                    // 短暂休眠，避免出现活锁  
                    Thread.sleep(3, RANDOM.nextInt(500));  
                }  
            } catch (Exception e) {  
                throw new RuntimeException("Locking error", e);  
            }  
		} finally {
			this.masterSlavePool.returnResource(jedis);
		}
        
        return this.locked;  
    }  
  
    /** 
     * 加锁 
     * 应该以： 
     * lock(); 
     * try { 
     *      doSomething(); 
     * } finally { 
     *      unlock()； 
     * } 
     * 的方式调用 
     * @return 成功或失败标志 
     */  
    public boolean lock(String key) {  
    
    	 return lock(key,DEFAULT_TIME_OUT); 
    }  
  
    /** 
     * 解锁 
     * 无论是否加锁成功，都需要调用unlock 
     * 应该以： 
     * lock(); 
     * try { 
     *      doSomething(); 
     * } finally { 
     *      unlock()； 
     * } 
     * 的方式调用 
     */  
    public void unlock(String key) {  
    	Jedis jedis = this.masterSlavePool.getMasterResource();
    	try {      	
            if (this.locked) {  
                jedis.del(key);  
            }  
        } finally { 
            this.masterSlavePool.returnResource(jedis); 
        }  
    }  
}